import datetime
import hashlib
import json
import logging
import time
import uuid
from decimal import Decimal

import pymongo

from base.connection import mongodb_util, redis_util
from base.request import ApiBaseHandler
from common.definition import (CashMethod, OrderStatus, OrderType, PayStatus, PayType, ret_msg)
from conf import config
from conf.config import DOMAIN
from daemon import tasks
from helper.api_helper import ApiHelper
from helper.beanstalkd import add_mq_cash_task, add_mq_task
from helper.coupon_helper import CouponHandler
from helper.payment.pay_util import generator_trade_no
from helper.payment.wechat_base import Wechat_Base
from helper.payment.wechat_pay import WechatPay
from helper.user import AddressHelper, UserHelper
from util.json_util import JSONEncoder
from util.math_util import convert2decimal

logger = logging.getLogger("wechat")


class UserInventory(ApiBaseHandler):
    async def get(self):
        class User(object):
            pass

        class UserInventory(object):
            pass

        class Goods(object):
            pass

        session = self.get_db_session([
            {"db_table": "ebt_user", "model": User},
            {"db_table": "ebt_user_inventory", "model": UserInventory},
            {"db_table": "sdet_goods", "model": Goods},
        ])
        open_id = await self.get_open_id()
        user = session.query(User).filter_by(ebf_user_id=open_id).first()
        page_index = int(self.get_parameter("page_index", 0))
        page_size = int(self.get_parameter("page_size", 10))
        ApiHelper.inspect_common_params(page_index, page_size)
        page_start = page_index * page_size

        if not open_id:
            logger.error("没有获取到open_id，请在微信打开！")
            session.close()
            return self.write(ret_msg(code=-1, error_message="请在微信打开！"))

        if not user:
            logger.info("创建用户: oid=%s" % open_id)
            await self.create_user(open_id, config.DEFAULT_AGENCY_UID)

        inventory = []
        pin_goods = session.query(UserInventory).filter_by(
            user_id=open_id, status=1).order_by(UserInventory.id.desc())[page_start:page_start + page_size]
        for g in pin_goods:
            goods = session.query(Goods).filter_by(sdef_goods_id=g.goods_id).first()
            if not goods:
                session.close()
                logger.error(f"商品不存在： goods_id={g.goods_id}")
                return self.write(ret_msg(f'ID为 "{g.goods_id}" 的商品不存在'))

            inventory.append({
                "goods_id": g.goods_id,
                "inventory": g.inventory,
                "goods_name": goods.sdef_goods_name,
                "goods_img": json.loads(goods.sdef_goods_thumbnail)[0],
                "status": g.status,
                "effect_time": g.effect_time.strftime("%Y-%m-%d") if g.effect_time else None,
                "expire_time": g.expire_time.strftime("%Y-%m-%d") if g.expire_time else None,
                "create_time": g.create_time.strftime("%Y-%m-%d") if g.create_time else None,
                "update_time": g.update_time.strftime("%Y-%m-%d") if g.update_time else None,
            })

        session.close()
        return self.write(ret_msg(data=inventory))


class PayConfirm(ApiBaseHandler):
    async def get(self):
        open_id = await self.get_open_id()
        order_type = OrderType.PINQU
        id_list = self.get_arguments("id")
        count_list = self.get_arguments("count")
        store_id = int(self.get_argument("store_id", 0))
        if len(id_list) != len(count_list):
            return self.write(ret_msg(code=-1, error_message="商品种类与商品数目不匹配"))

        if not id_list or not count_list:
            return self.write(ret_msg(code=-1, error_message="商品种类或商品数目参数不能为空"))

        cart_goods_array = []
        goods_list = []
        goods_packing_id = ["571983673114813", "571983568187916"]  # 商品包装ID列表
        price_total = Decimal(0)
        delivery_fee = 0
        unit_fee = 0  # 邮费或管理费/支
        for index, item in enumerate(id_list):
            goods_list.append(dict(id=item, count=int(count_list[index])))

        class Goods(object):
            pass

        class StoreGoods(object):
            pass

        class GoodsOrder(object):
            pass

        class UserAddress(object):
            pass

        class UserInventory(object):
            pass

        class User(object):
            pass

        class Agency(object):
            pass

        class UserAgency(object):
            pass

        session = self.get_db_session([
            {"db_table": "sdet_goods", "model": Goods},
            {"db_table": "sdet_store_goods", "model": StoreGoods},
            {"db_table": "sdet_order", "model": GoodsOrder},
            {"db_table": "sdet_address", "model": UserAddress},
            {"db_table": "ebt_user_inventory", "model": UserInventory},
            {"db_table": "ebt_user", "model": User},
            {"db_table": "ebt_agency", "model": Agency},
            {"db_table": "ebt_user_agency", "model": UserAgency}
        ])

        user = session.query(User).filter_by(ebf_user_id=open_id).first()
        if user:
            nickname = user.ebf_user_nickname
            if nickname == "未关注" or nickname == "" or nickname is None:
                await self.update_nickname(open_id)

        store_name = None
        if store_id:
            agency = session.query(Agency).filter_by(ebf_agency_id=store_id).first()
            if agency:
                store_name = agency.ebf_agency_name

        for c in goods_list:
            count = int(c["count"])
            goods_id = c["id"]
            if store_id:
                filters = dict(
                    sdef_goods_store_id=store_id,
                    sdef_goods_id=goods_id,
                    sdef_goods_factory_uid=config.FACTORY_UID
                )
                goods = session.query(StoreGoods).filter_by(**filters).first()
            else:
                goods = session.query(Goods).filter_by(sdef_goods_id=goods_id).first()

            if not goods:
                logger.error(f"商品不存在： goods_id={goods_id} store_id={store_id}")
                session.close()
                return self.write(ret_msg(f'ID为 "{goods_id}" 的商品不存在'))

            balance_rate = 0
            if goods_id in goods_packing_id:
                goods_price = goods.sdef_goods_price
            else:
                delivery_fee += unit_fee * count
                goods_price = Decimal(0)

            goods = dict(
                id=goods_id,
                count=count,
                goods_inventory=goods.sdef_goods_count,
                balance_rate=balance_rate,
                goods_img=json.loads(goods.sdef_goods_thumbnail)[0],
                goods_name=goods.sdef_goods_name,
                goods_price=str(goods_price.quantize(Decimal("0.00"))),
            )
            price_total += goods_price * Decimal(count)
            cart_goods_array.append(goods)

        default_address = AddressHelper.get_default(open_id)
        use_address = AddressHelper.get_use(open_id)
        db = mongodb_util.db
        address = None
        if use_address:
            logger.debug("使用地址: address_id=%s" % use_address["address_id"])
            address = session.query(UserAddress).filter_by(sdef_address_id=use_address["address_id"]).first()
        elif default_address:
            logger.debug("默认地址: address_id=%s" % default_address["address_id"])
            address = session.query(UserAddress).filter_by(sdef_address_id=default_address["address_id"]).first()
        else:
            result = db.sdec_address.find({
                "user_id": open_id,
                "is_delete": False
            }).sort("update_time", pymongo.DESCENDING)

            for a in result:
                address = session.query(UserAddress).filter_by(sdef_address_id=a["address_id"]).first()
                break

        if address:
            address_info = dict(
                province=address.sdef_address_province,
                city=address.sdef_address_city,
                county=address.sdef_address_county,
                detail=address.sdef_address_detail,
                name=address.sdef_address_name,
                phone=address.sdef_address_phone
            )
        else:
            address_info = {}

        wechat_fee = price_total + delivery_fee
        redis = redis_util.client
        unique_str = str(uuid.uuid1())  # 页面唯一字符串，避免多次重复请求，重复支付
        redis.setex("unique_string_%s" % unique_str, 600, 10)
        context = dict(
            cart_goods_array=cart_goods_array,
            price_total=str(price_total.quantize(Decimal("0.00"))),
            delivery_fee=delivery_fee,
            wechat_fee=str(wechat_fee.quantize(Decimal("0.00"))),
            address=address_info,
            unique_str=unique_str,
            goods_list=goods_list,
            order_type=order_type,
            store_name=store_name,
            store_id=store_id
        )
        session.close()
        return self.write(ret_msg(data=context))

    async def post(self):
        open_id = await self.get_open_id()
        ip = self.request.remote_ip

        pay_type = int(self.get_parameter("pay_type", PayType.WECHAT))
        # 订单类型（1=普通订单，2=送礼订单，3=加盟费订单，4=特惠订单，5=餐券抵扣订单，6=礼品卡订单，7=新礼品订单，8=体验卡买单订单）
        order_type = int(self.get_parameter("order_type", OrderType.PINQU))
        store_id = int(self.get_parameter("store_id", 0))
        message = self.get_parameter("message", None)
        url = self.get_parameter("url", None)  # 用户请求该接口前所在的页面完整地址
        unique_str = self.get_parameter("unique_str")
        redis = redis_util.client
        unique_string = redis.get("unique_string_%s" % unique_str)
        if not unique_string:
            return self.write(ret_msg(code=-1, error_message="页面已失效，请返回上一页面重新支付！"))

        if pay_type != PayType.WECHAT:
            return self.write(ret_msg(code=-1, error_message="目前只支持微信支付"))

        class UserAddress(object):
            pass

        class GoodsOrder(object):
            pass

        class Goods(object):
            pass

        class StoreGoods(object):
            pass

        class Carts(object):
            pass

        class User(object):
            pass

        class AccountMoney(object):
            pass

        class Agency(object):
            pass

        class UserAgency(object):
            pass

        class UserInventory(object):
            pass

        session = self.get_db_session([
            {"db_table": "sdet_goods", "model": Goods},
            {"db_table": "sdet_store_goods", "model": StoreGoods},
            {"db_table": "sdet_cart", "model": Carts},
            {"db_table": "sdet_order", "model": GoodsOrder},
            {"db_table": "sdet_address", "model": UserAddress},
            {"db_table": "ebt_user", "model": User},
            {"db_table": "ebt_account_money", "model": AccountMoney},
            {"db_table": "ebt_agency", "model": Agency},
            {"db_table": "ebt_user_agency", "model": UserAgency},
            {"db_table": "ebt_user_inventory", "model": UserInventory},
        ])

        default_address = AddressHelper.get_default(open_id)
        use_address = AddressHelper.get_use(open_id)
        db = mongodb_util.db
        address = None
        if use_address:
            logger.debug("使用地址，address_id=%s" % use_address["address_id"])
            address = session.query(UserAddress).filter_by(sdef_address_id=use_address["address_id"]).first()
        elif default_address:
            logger.debug("默认地址，address_id=%s" % default_address["address_id"])
            address = session.query(UserAddress).filter_by(sdef_address_id=default_address["address_id"]).first()
        else:
            result = db.sdec_address.find({"user_id": open_id, "is_delete": False}).sort("update_time",
                                                                                         pymongo.DESCENDING)
            for a in result:
                address = session.query(UserAddress).filter_by(sdef_address_id=a["address_id"]).first()
                if address:
                    break

        # 送礼订单允许地址为空
        if not address and not store_id:
            session.close()
            return self.write(ret_msg(code=-1, error_message="请先完善收货地址"))

        cart_goods = self.get_parameter("goods_list", [])
        goods_packing_id = ["571983673114813", "571983568187916"]  # 商品包装ID列表
        cart_goods_array = []
        price_total = Decimal("0")
        delivery_fee = 0
        unit_fee = 0  # 邮费或管理费/支

        if not isinstance(cart_goods, list):
            cart_goods = json.loads(cart_goods)

        if not cart_goods:
            session.close()
            return self.write(ret_msg(-1, error_message="缺少请求参数商品编号和数量！"))

        # if not store_id and len(cart_goods) == 1:
        #     if "深圳" not in address.sdef_address_city:
        #         session.close()
        #         return self.write(ret_msg(-1, error_message="原包装只支持深圳市包邮！"))

        for c in cart_goods:
            goods_id = c["id"]
            count = int(c["count"])
            if store_id:
                filters = dict(
                    sdef_goods_store_id=store_id,
                    sdef_goods_id=goods_id,
                    sdef_goods_factory_uid=config.FACTORY_UID
                )
                goods = session.query(StoreGoods).filter_by(**filters).first()
            else:
                goods = session.query(Goods).filter_by(sdef_goods_id=goods_id).first()

            if not goods:
                logger.error(f"商品不存在： goods_id={goods_id}")
                session.close()
                return self.write(ret_msg(-1, error_message=f"ID为{goods_id}的商品不存在"))

            if goods.sdef_goods_status != 1 and goods_id not in goods_packing_id:
                logger.error(f"商品已下架： goods_id={goods_id}")
                session.close()
                return self.write(ret_msg(-1, error_message=f"ID为{goods_id}的商品已下架"))

            filters2 = dict(
                user_id=open_id,
                status=1,
                goods_id=goods_id
            )
            goods_name = goods.sdef_goods_name
            goods_img = json.loads(goods.sdef_goods_thumbnail)[0]
            balance_rate = 0
            # goods_price = goods.sdef_goods_member_price if is_membership else goods.sdef_goods_price
            if goods_id in goods_packing_id:
                goods_price = goods.sdef_goods_price
            else:
                delivery_fee += unit_fee * count
                goods_price = Decimal(0)

            # 检查商品是否限购
            if goods.sdef_goods_limit_num != 0:
                if goods.sdef_goods_limit_num < count:
                    goods_limit_num = goods.sdef_goods_limit_num
                    session.close()
                    return self.write(ret_msg(-1, error_message=f"{goods_name}超出限购数量{goods_limit_num}"))

            # 下单时减少库存
            if store_id:
                # 店内取酒，减少库存
                if goods.sdef_goods_count >= count:
                    logger.info(f"old_goods_count={goods.sdef_goods_count} count={count}")
                    goods.sdef_goods_count -= count
                else:
                    session.close()
                    return self.write(ret_msg(-1, error_message=f"{goods_name}商品库存不足"))
            else:
                # 公司发货酒不需要减少库存，包装减少库存
                if goods_id in goods_packing_id:
                    if goods.sdef_goods_count >= count:
                        logger.info(f"old_goods_count={goods.sdef_goods_count} count={count}")
                        goods.sdef_goods_count -= count
                    else:
                        logger.error(f"包装库存不足： goods_id={goods_id}")

            if goods_id not in goods_packing_id:
                ui = session.query(UserInventory).filter_by(**filters2).first()
                if not ui:
                    logger.error(f"用户库存中没有该商品: goods_id={goods_id}")
                    session.close()
                    return self.write(ret_msg(-1, error_message=f"没有拼柜{goods_name}"))

                inventory = ui.inventory
                if count > inventory:
                    logger.error(f"用户个人库存不足: goods_id={goods_id}")
                    session.close()
                    return self.write(ret_msg(-1, error_message=f"用户拼柜{goods_name}库存不足"))

            goods = dict(
                id=goods_id,
                count=count,
                goods_img=goods_img,
                goods_name=goods_name,
                goods_price=goods_price,
                goods_member_price=goods.sdef_goods_member_price,
                goods_pin_price=goods.sdef_goods_pin_price,
                balance_rate=balance_rate,
                rate=goods.sdef_goods_rate,
                master_rate=goods.sdef_goods_master_rate,
                invite_rate=goods.sdef_goods_invite_rate,
                invite_invite_rate=goods.sdef_goods_invite_invite_rate,
                career_rate=goods.sdef_goods_career_rate,
                invite_career_rate=goods.sdef_goods_invite_career_rate,
                supplier=goods.sdef_goods_supplier,
                goods_cost=goods.sdef_goods_cost,
            )
            price_total += goods_price * Decimal(count)
            cart_goods_array.append(goods)

        wechat_fee = price_total + delivery_fee
        logger.info("price_total=%s,delivery_fee=%s,wechat_fee=%s" % (price_total, delivery_fee, wechat_fee))
        if wechat_fee < Decimal("0.01"):
            pay_type = PayType.BALANCE  # 支付方式直接标记为余额支付

        now = datetime.datetime.now()
        out_trade_no = generator_trade_no()
        goods_order = GoodsOrder()
        goods_order.sdef_order_id = out_trade_no
        goods_order.sdef_order_factory_uid = config.FACTORY_UID
        goods_order.sdef_order_device_id = open_id
        goods_order.sdef_order_fee = wechat_fee
        goods_order.sdef_order_goods = json.dumps(cart_goods_array, cls=JSONEncoder)
        goods_order.sdef_order_name = "思达尔商城订单"
        goods_order.sdef_order_message = message
        goods_order.sdef_order_describe = "微信商城订单"
        goods_order.sdef_order_pay_type = pay_type
        goods_order.sdef_order_type = order_type
        goods_order.sdef_order_ip = ip
        goods_order.sdef_order_delivery_fee = delivery_fee  # 邮费或管理费
        goods_order.sdef_order_create_time = now
        goods_order.sdef_order_store_id = store_id

        if pay_type == PayType.WECHAT:
            goods_order.sdef_order_status = OrderStatus.WAIT_PAY
            goods_order.sdef_order_pay_status = PayStatus.NOT_PAY
        else:
            goods_order.sdef_order_status = OrderStatus.WAIT_EXPRESS
            goods_order.sdef_order_pay_status = PayStatus.SUCCESS
            goods_order.sdef_order_pay_time = now

        if not store_id:
            goods_order.sdef_order_address_id = address.sdef_address_id
        else:
            goods_order.sdef_order_ship_type = 2

        # 获取当前用户所属的合伙人填入订单中（没有合伙人的使用默认合伙人的uid）
        agency_uid = config.DEFAULT_AGENCY_UID
        users = session.query(User).filter_by(ebf_user_id=open_id).all()
        if len(users) == 1:
            user = users[0]
            if user.ebf_user_agency_uid:
                agency_uid = user.ebf_user_agency_uid

        goods_order.sdef_order_agency_uid = agency_uid
        session.add(goods_order)

        redis.delete("unique_string_%s" % unique_str)
        redis.setex("order_id_%s" % out_trade_no, 86400, out_trade_no)

        if pay_type == PayType.BALANCE:
            logger.info(f"余额支付: order_id={out_trade_no}")
            context = dict(
                trade_no=out_trade_no,
                pay_type=pay_type
            )
            if store_id:
                # 8小时之后自动确认收货
                if not add_mq_task(out_trade_no, message_type=6, delay=8 * 3600):
                    logger.info(f"8小时后自动确认收货加入任务队列失败：order_id={out_trade_no}")

            # 6分钟后检查是否已减用户库存
            if not add_mq_task(out_trade_no, message_type=1, delay=360):
                logger.error(f"6分钟后检查是否已减用户库存加入消息队列失败: order_id={out_trade_no}")
            tasks.order_paid.delay(out_trade_no)
            tasks.cloud_print_order.delay(out_trade_no)
            is_minus, msg = self.minus_user_inventory(out_trade_no, open_id, cart_goods_array, redis)
            if not is_minus:
                session.close()
                return self.write(ret_msg(code=-1, error_message=msg))
            session.commit()
            session.close()
            return self.write(ret_msg(data=context))

        try:
            session.commit()
        except Exception as e:
            logger.exception(e)
            session.rollback()
            session.close()
            return self.write(ret_msg(code=-1, error_message="订单创建异常"))

        app_id = config.MP_APP_ID
        time_stamp = int(str(time.time()).split(".")[0])
        nonce_str = WechatPay.generate_nonce_str()
        logger.info("生成预支付交易单")

        try:
            prepay_id = WechatPay.order(out_trade_no, int(wechat_fee * 100), "商城订单", ip, nonce_str, open_id)

            if use_address and not store_id:
                if default_address:
                    if use_address["address_id"] != default_address["address_id"]:
                        is_default = True
                        is_use = True
                        AddressHelper.set_default(open_id, default_address["address_id"], is_default, is_use)
                else:
                    is_default = False
                    is_use = False
                    AddressHelper.set_default(open_id, use_address["address_id"], is_default, is_use)
        except Exception as e:
            logger.exception(e)
            session.close()
            return self.finish(ret_msg(code=-1, error_message="支付异常"))

        package = "prepay_id=" + prepay_id
        # 计算jsapi签名
        logger.info("计算jsapi签名" + package)
        sign_value = WechatPay.get_jsapi_pay_sign(time_stamp, nonce_str, package, "MD5")
        jsapi_ticket = self.get_jsapi_ticket()
        signature = Wechat_Base.signature(nonce_str, time_stamp, url, jsapi_ticket)
        logger.debug("signature：%s url: %s" % (signature, url))

        # 微信支付的加入消息队列，6分钟后检查是否已支付
        if not add_mq_task(out_trade_no, message_type=1, delay=360):
            logger.error(f"6分钟后检查是否已支付加入消息队列失败: order_id={out_trade_no}")

        context = dict(
            trade_no=out_trade_no,
            app_id=app_id,
            time_stamp=str(time_stamp),
            nonce_str=nonce_str,
            sign_value=sign_value,
            prepay_id=prepay_id,
            signature=signature,
            full_url=url,
            order_type=order_type,
            pay_type=pay_type,
        )
        session.close()
        return self.write(ret_msg(data=context))

    def minus_user_inventory(self, order_id, open_id, cart_goods, redis):
        """减少用户库存"""

        class UserInventory(object):
            pass

        session = self.get_db_session([
            {"db_table": "ebt_user_inventory", "model": UserInventory},
        ])

        goods_packing_id = ["571983673114813", "571983568187916"]  # 商品包装ID列表
        goods_info = list(filter(lambda g: g["id"] not in goods_packing_id, cart_goods))[0]
        goods_id = goods_info["id"]
        count = goods_info["count"]
        filters = dict(
            user_id=open_id,
            goods_id=goods_id,
            status=1
        )
        ui = session.query(UserInventory).filter_by(**filters).first()
        if not ui:
            logger.error(f"用户没有该商品库存: order_id={order_id}")
            session.close()
            return False, "用户没有该商品库存"

        pinqu_id = redis.get(f"pinqu_{order_id}")
        access_record = ui.access_record
        logger.info(f"access_record={access_record}")
        is_minus = order_id in access_record
        if not is_minus and not pinqu_id:
            logger.info(f"minus_inventory: order_id={order_id} old_inventory={ui.inventory} count=-{count}")
            redis.setex(f"pinqu_{order_id}", 3600, 1)
            access_record = json.loads(access_record)
            access_record["minus"].append({order_id: count})
            ui.access_record = json.dumps(access_record)
            ui.update_time = datetime.datetime.now()
            ui.inventory -= count
            session.commit()
        else:
            logger.error(f"用户商品库存已减: order_id={order_id} old_inventory={ui.inventory} count=-{count}")
            session.close()
            return False, "用户商品库存已减"

        session.close()
        return True, "ok"


class UserCashApplyHandler(ApiBaseHandler):
    async def post(self, *args, **kwargs):
        open_id = await self.get_open_id()

        cash_method = int(self.json_args.get("cash_method"))
        if cash_method not in [CashMethod.WECHAT]:
            logger.error(f"余额提现: 不支持的结算方式 open_id={open_id}")
            return self.finish(ret_msg(-1, error_message="不支持的结算方式"))

        fee = self.json_args.get("fee", None)
        if not fee:
            logger.error(f"余额提现: 没有提现金额 open_id={open_id}")
            return self.finish(ret_msg(-1, error_message="请输入提现金额"))
        fee = Decimal(fee).quantize(Decimal("0.00"))
        if cash_method == CashMethod.WECHAT:
            if not (Decimal("1") <= fee <= Decimal("20000")):
                logger.error(f"余额提现: 提现到微信钱包最少1元，最多20000元 open_id={open_id} fee={fee}")
                return self.finish(ret_msg(-1, error_message="提现到微信钱包最少1元，最多20000元"))

        name = self.json_args.get("name", None)
        if cash_method == CashMethod.WECHAT and not name:
            logger.error(f"余额提现: 没有实名 open_id={open_id}")
            return self.finish(ret_msg(40010))

        class AccountMoney(object):
            pass

        session = self.get_db_session([
            {"db_table": "ebt_account_money", "model": AccountMoney},
        ])

        account_money = session.query(AccountMoney).filter_by(ebf_am_user_id=open_id).first()
        if not account_money:
            session.close()
            logger.error(f"余额提现: 用户没有余额账户 open_id={open_id}")
            return self.finish(ret_msg(-1, error_message="用户没有余额"))

        enable_fee = convert2decimal(account_money.ebf_am_cash)

        logger.info(f"余额提现: 开始申请 open_id={open_id}, enable_fee={enable_fee}, fee={fee}")

        # 检查提现金额是否大于可提现金额
        if fee > enable_fee:
            session.close()
            logger.error(f"余额提现: 申请的金额大于可提现金额 open_id={open_id}, enable_fee={enable_fee}, fee={fee}")
            return self.finish(ret_msg(-1, error_message="申请的金额大于可提现金额"))

        ip = self.request.remote_ip

        # 普通用户可提现余额提现
        agency_uid = ""

        add_mq_cash_task(open_id, cash_method, agency_uid, fee, name, ip)
        session.close()
        logger.info(f"余额提现: 提现申请已提交 open_id={open_id}, enable_fee={enable_fee}, fee={fee}")
        return self.finish(ret_msg(error_message="提现申请已提交，请以实际申请结果为准"))


class UserName(ApiBaseHandler):
    async def get(self):
        open_id = await self.get_open_id()

        class User(object):
            pass

        session = self.get_db_session([
            {"db_table": "ebt_user", "model": User},
        ])

        user = session.query(User).filter_by(ebf_user_id=open_id).first()
        if not user:
            session.close()
            logger.error(f"user表无记录: open_id={open_id}")
            return self.write(ret_msg(-1, error_message="请先关注公众号"))

        name = user.ebf_user_name
        session.close()
        return self.write(ret_msg(data=name))

    async def post(self):
        open_id = await self.get_open_id()
        name = self.json_args.get("name", None)
        if not name:
            return self.write(ret_msg(-1, error_message="缺少请求参数姓名"))

        class User(object):
            pass

        session = self.get_db_session([
            {"db_table": "ebt_user", "model": User},
        ])

        user = session.query(User).filter_by(ebf_user_id=open_id).first()
        if not user:
            session.close()
            logger.error(f"user表无记录: open_id={open_id}")
            return self.write(ret_msg(-1, error_message="请先关注公众号"))

        user.ebf_user_name = name
        session.commit()
        session.close()
        return self.write(ret_msg())


class Activity(ApiBaseHandler):
    async def get(self):
        class CouponUser(object):
            pass

        session = self.get_db_session([
            {"db_table": "ebt_coupon_user", "model": CouponUser}
        ])

        open_id = await self.get_open_id()
        filters = dict(
            coupon_id=6,
            order_id="00000000000000000",
            status=0,
            user_id=open_id,
            is_active=1
        )
        cu = session.query(CouponUser).filter_by(**filters).first()
        if cu:
            data = 1
        else:
            data = 0

        session.close()
        return self.write(ret_msg(data=data))

    async def post(self):
        class CouponUser(object):
            pass

        session = self.get_db_session([
            {"db_table": "ebt_coupon_user", "model": CouponUser}
        ])

        open_id = await self.get_open_id()
        filters = dict(
            coupon_id=6,
            order_id="00000000000000000",
            status=0,
            user_id=open_id,
            is_active=1
        )
        cu = session.query(CouponUser).filter_by(**filters).first()
        if cu:
            logger.error(f"用户已领券: open_id={open_id}")
            session.close()
            return self.write(ret_msg())
        else:
            result = CouponHandler.create_coupon(open_id, 6)
            if result:
                logger.info(f"get coupon success: open_id={open_id}")
                session.close()
                return self.write(ret_msg())
            else:
                logger.error(f"get coupon fail: open_id={open_id}")
                session.close()
                return self.write(ret_msg(code=-1, error_message="优惠券领券失败，请重试！"))


class VipCard(ApiBaseHandler):
    async def post(self):
        """
        创建一个会员卡
        """

        open_id = await self.get_open_id()
        uid = config.FACTORY_UID
        base_url = f"https://{DOMAIN}/v/"

        class VipCard(object):
            pass

        session = self.get_db_session([{"db_table": "ebt_vip_card", "model": VipCard}])
        vip_card = session.query(VipCard).order_by(VipCard.id.desc()).first()
        if vip_card:
            card_id = vip_card.id
            start_id = card_id + 1
        else:
            start_id = 10000001

        now = datetime.datetime.now()
        try:
            code_str = f"{uid}{start_id}"
            m = hashlib.md5()
            m.update(code_str.encode())
            code = m.hexdigest().upper()
            url = f"{base_url}{start_id}/{code}"

            vip = VipCard()
            vip.id = start_id
            vip.code = code
            vip.status = 1
            vip.create_time = now
            vip.update_time = now
            session.add(vip)
            session.commit()
            session.close()

            data = {
                "id": start_id,
                "code": code,
                "vip_link": url,
            }
            return self.write(ret_msg(data=data))
        except Exception as e:
            logger.exception(f"创建VIP失败：{e}")
            session.close()
            return self.write(ret_msg(-1, error_message="创建VIP失败，请稍后再试"))

    async def get(self):
        """
        获取一个会员卡
        """
        vip_id = self.get_parameter("id", None)
        code = self.get_parameter("code", None)
        if not vip_id or not code:
            self.write(ret_msg(-1, error_message="参数错误"))

        vip_id = int(vip_id)
        open_id = await self.get_open_id()

        class VipCard(object):
            pass

        session = self.get_db_session([{"db_table": "ebt_vip_card", "model": VipCard}])
        vip = session.query(VipCard).filter_by(id=vip_id).first()
        if not vip:
            logger.error(f"VIP: NG vip {vip_id} 不存在！")
            self.write(ret_msg(-1, error_message="VIP卡不存在！"))

        if code != vip.code:
            logger.error(f"VIP: NG vip {vip_id} code {code} 错误！")
            self.write(ret_msg(-1, error_message="VIP卡密钥错误"))

        UserHelper.update_user_level(open_id, 10)
        logger.info(f"update_user_level: open_id={open_id}, level=10")
        return self.write(ret_msg())
